/* Copyright (c) 2008, RDFfs - Andrea Marchesini <baku@morlardf.net>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#else
# error Use configure; make; make install
#endif

#include <rdffs.h>

static gchar *retcode_string (gint ret);
static size_t memorize_file (void *ptr, size_t size, size_t nmemb,
			     void *data);

gboolean
rdffs_download (gchar * url, gchar ** content, gsize * length,
		GError ** error)
{
  GString *string = NULL;

  CURL *curl;
  CURLcode ret;
  long retcode;

  curl_global_init (CURL_GLOBAL_DEFAULT);
  if (!(curl = curl_easy_init ()))
    {
      g_set_error (error, 0, 0, "Error initializing libCurl");
      return FALSE;
    }

  curl_easy_setopt (curl, CURLOPT_URL, url);
  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, memorize_file);
  curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1);
  curl_easy_setopt (curl, CURLOPT_FILE, (void *) &string);
  curl_easy_setopt (curl, CURLOPT_ENCODING, "gzip, deflate");

  curl_easy_setopt (curl, CURLOPT_USERAGENT, PACKAGE " " VERSION);

  if ((ret = curl_easy_perform (curl)) || !string
      || curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE,
			    &retcode) != CURLE_OK || ((retcode < 200
						       || retcode >= 300)
						      && retcode != 0))
    {
      if (string)
	g_string_free (string, TRUE);

      curl_easy_cleanup (curl);

      if (ret != CURLE_OK)
	g_set_error (error, 0, 0, "%s", curl_easy_strerror (ret));

      else
	g_set_error (error, 0, 0, "Download status is %d: %s", (gint) retcode,
		     retcode_string ((gint) retcode));

      return FALSE;
    }

  curl_easy_cleanup (curl);

  *length = string->len;
  *content = g_string_free (string, FALSE);

  return TRUE;
}

static size_t
memorize_file (void *ptr, size_t size, size_t nmemb, void *data)
{
  register int realsize = size * nmemb;
  GString **string = (GString **) data;

  if (!*string)
    *string = g_string_new (NULL);

  *string = g_string_append_len (*string, ptr, realsize);
  return realsize;
}

static gchar *
retcode_string (gint ret)
{
  switch (ret)
    {
    case 400:
      return " Bad Request";
    case 401:
      return " Unauthorized";
    case 402:
      return " Payment Required";
    case 403:
      return " Forbidden";
    case 404:
      return " Not Found";
    case 405:
      return " Method Not Allowed";
    case 406:
      return " Not Acceptable";
    case 407:
      return " Proxy Authentication Required";
    case 408:
      return " Request Timeout";
    case 409:
      return " Conflict";
    case 500:
      return " Internal Server Error";
    case 501:
      return " Not Implemented";
    case 502:
      return " Bad Gateway";
    case 503:
      return " Service Unavailable";

    default:
      return "";
    }
}

/* EOF */
